home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 422_02 / cutil / ccref.c < prev    next >
C/C++ Source or Header  |  1994-03-20  |  8KB  |  336 lines

  1. /*
  2.  * Simple 'C' cross reference listing generator
  3.  *
  4.  * This program generates a line-numbered listing of a 'C' program, with
  5.  * A cross reference table of all global symbols showing their definition,
  6.  * and any references to them.
  7.  *
  8.  * The program does minimal parsing of the 'C' code, and as such has the
  9.  * following limitations:
  10.  *
  11.  * - The first time a symbol is encountered outside of a function definition
  12.  *   is considered to be its definition. This is usually the case, however for
  13.  *   symbols #defined in external header files etc, which are used in the
  14.  *   definition of other global entities, the first use is considered the
  15.  *   definition.
  16.  *
  17.  * - Local symbols having names which are identical to a global symbol are
  18.  *   reported as references.
  19.  *
  20.  * - Symbols not defined in the file which don't have an explict "extern"
  21.  *   declaration are not reported. To track library functions etc. which
  22.  *   fall into this catagory, place an "extern int func()" declaration at
  23.  *   the start of the file.
  24.  *
  25.  * Copyright 1993-1994 Dave Dunfield
  26.  * All rights reserved.
  27.  *
  28.  * Permission granted for personal (non-commercial) use only.
  29.  *
  30.  * Compile command: cc ccref -fop
  31.  */
  32. #include <stdio.h>
  33.  
  34. #define    SYMBOLS        500        /* Maximum number of symbols */
  35. #define    SYMBOL_POOL    5000    /* String space for symbol storage */
  36. #define    REFERENCES    10000    /* Maximum number of references */
  37.  
  38. /* Symbol table and associated management variables */
  39. char symbol_pool[SYMBOL_POOL], *symbol_names[SYMBOLS];
  40. int references[REFERENCES], ref_list[SYMBOLS], pool_top = 0, name_top = 0,
  41.     ref_top = 0;
  42.  
  43. /* Command line switch variables */
  44. char list = -1, filename[66];
  45. int page_width = 79, page_length = 60, tab_size = 4;
  46.  
  47. /* Misc. housekeeping variables */
  48. char in_string = 0, in_comment = 0, *optr, pass = 0;
  49. int bracket = 0, line_number, page_number = 0, pcount = 9999;
  50.  
  51. /* Table of MICRO-C reserved words */
  52. char *reserved_words[] = {
  53.     "int", "unsigned", "char", "static", "extern", "register", "struct",
  54.     "union", "if", "else", "while", "do", "for", "switch", "case",
  55.     "default", "return", "break", "continue", "goto", "sizeof",
  56.     "asm", "#define", "#ifdef", "#ifndef", "#else", "#endif",
  57.     "#undef", "#forget", 0 };            /* end of table */
  58.  
  59. /*
  60.  * Main program
  61.  */
  62. main(argc, argv)
  63.     int argc;
  64.     char *argv[];
  65. {
  66.     int i, j, k, l;
  67.     char buffer[200], symbol[50], *sptr, c, last_def;
  68.     FILE *fp;
  69.  
  70.     if(argc < 2)
  71.         abort("\nUse: CCREF <filename> [-list p=page_length t=tab_size w=page_width]\n\nCopyright 1993-1994 Dave Dunfield\nAll rights reserved.\n");
  72.  
  73.     sptr = argv[1];
  74.     i = j = 0;
  75.     do {
  76.         if((filename[i++] = c = toupper(*sptr++)) == '.')
  77.             j = -1; }
  78.     while(c);
  79.     if(!j) {
  80.         filename[i-1] = '.';
  81.         filename[i] = 'C';
  82.         filename[i+1] = 0; }
  83.     fp = fopen(filename, "rvq");
  84.  
  85.     for(i=2; i < argc; ++i) {
  86.         sptr = argv[i];
  87.         switch((toupper(*sptr++) << 8) | toupper(*sptr++)) {
  88.             case 'W=' :        /* Specify page width */
  89.                 page_width = atoi(sptr);
  90.                 break;
  91.             case 'T=' :        /* Specify tab size */
  92.                 tab_size = atoi(sptr);
  93.                 break;
  94.             case 'P=' :        /* Specify page length */
  95.                 page_length = atoi(sptr);
  96.                 break;
  97.             case '-L' :        /* Inhibit line numbered listing */
  98.                 list = 0;
  99.                 break;
  100.             default:
  101.                 printf("Invalid argument: %s\n", argv[i]);
  102.                 exit(-1); } }
  103.  
  104. again:
  105.     line_number = 0;
  106.     while(fgets(optr = buffer, sizeof(buffer)-1, fp)) {
  107.         ++line_number;
  108.         if(list && !pass) {
  109.             title("Program Listing");
  110.             printf("%5u ", line_number);
  111.             i = 0;
  112.             while(c = *optr++) {
  113.                 if(c == '\t') {            /* tab */
  114.                     if((i + tab_size) > (page_width - 6)) {
  115.                         putc('\n', stdout);
  116.                         title("Program Listing");
  117.                         printf("      ");
  118.                         i = 0; }
  119.                     do
  120.                         putc(' ', stdout);
  121.                     while(++i % tab_size); }
  122.                 else {
  123.                     if(++i > (page_width - 6)) {
  124.                         putc('\n', stdout);
  125.                         title("Program Listing");
  126.                         printf("      ");
  127.                         i = 0; }
  128.                     putc(c, stdout); } }
  129.             putc('\n', stdout);
  130.             optr = buffer; }
  131.         if(strbeg(buffer, "#include"))
  132.             continue;
  133.         do {
  134.             if(in_string) switch(c = *optr) {
  135.                 default:
  136.                     if(c == in_string)
  137.                         in_string = 0;
  138.                     continue;;
  139.                 case '\\' :
  140.                     ++optr;
  141.                     continue; }
  142.             if(in_comment) switch(c = *optr) {
  143.                 case '/' :
  144.                     if(*(optr+1) == '*') {
  145.                         ++optr;
  146.                         ++in_comment; }
  147.                     continue;
  148.                 case '*' :
  149.                     if(*(optr+1) == '/') {
  150.                         ++optr;
  151.                         --in_comment; }
  152.                 default:
  153.                     continue; }
  154.             switch(c = *optr) {
  155.                 case '{' :
  156.                     ++bracket;
  157.                     continue;
  158.                 case '}' :
  159.                     --bracket;
  160.                     continue;
  161.                 case '/' :
  162.                     if(*(optr+1) == '*') {
  163.                         in_comment = 1;
  164.                         ++optr; }
  165.                     continue;
  166.                 case '(' :
  167.                     if(last_def == 1) {
  168.                         in_string = '{';
  169.                         ++bracket; }
  170.                     continue;
  171.                 case '\'' :
  172.                 case '\"' :
  173.                     in_string = c;
  174.                     continue;
  175.                 case ' ' :
  176.                 case '\t' :
  177.                     continue; }
  178.             last_def = 0;
  179.             if(issymbol(c)) {
  180.                 sptr = symbol;
  181.                 while(issymbol(*optr) || isdigit(*optr))
  182.                     *sptr++ = *optr++;
  183.                 *sptr = 0;
  184.                 --optr;
  185.                 for(i=0; sptr = reserved_words[i]; ++i)
  186.                     if(!strcmp(symbol, sptr))
  187.                         goto skip_symbol;
  188.                 if(bracket) {
  189.                     if(pass)
  190.                         reference(symbol); }
  191.                 else {
  192.                     if(!pass)
  193.                         define(symbol);
  194.                     last_def = 1; }
  195.                 skip_symbol: } }
  196.         while(*optr++); }
  197.     if(!pass) {
  198.         pass = 1;
  199.         rewind(fp);
  200.         ref_list[name_top] = ref_top;
  201.         goto again; }
  202.     fclose(fp);
  203.  
  204.     pcount = 9999;
  205.     title("Cross Reference");
  206.     printf("    Symbol       Def  References\n");
  207.     title("Cross Reference");
  208.     printf("--------------- ----- ");
  209.     for(l=22; l < page_width; ++l)
  210.         putc('-', stdout);
  211.     putc('\n', stdout);
  212.  
  213.     for(;;) {
  214.         i = 0;
  215.         while(!symbol_names[i])
  216.             if(++i >= name_top)
  217.                 return;
  218.         for(j=i+1; j < name_top; ++j)
  219.             if((sptr = symbol_names[j]) && (strcmp(sptr, symbol_names[i]) < 0))
  220.                 i = j;
  221.         title("Cross Reference");
  222.         printf("%-15s %-5u", symbol_names[i], references[j = ref_list[i]]);
  223.         k = ref_list[i+1]-1;
  224.         l = 0;
  225.         while(j < k) {
  226.             if((l += 6) > (page_width-21)) {
  227.                 l = 6;
  228.                 printf("\n%-21s", ""); }
  229.             printf(" %5u", references[++j]); }
  230.         putc('\n', stdout);
  231.         symbol_names[i] = 0; }
  232. }
  233.  
  234. /*
  235.  * Test for valid 'C' symbol character.
  236.  * Also allow '#', so that we can detect '#' directives. This should
  237.  * not conflict with 'C' source since '#' is otherwise not permitted.
  238.  */
  239. issymbol(c)
  240.     int c;
  241. {
  242.     return    ((c >= 'a') && (c <= 'z'))
  243.         ||    ((c >= 'A') && (c <= 'Z'))
  244.         ||    (c == '_')
  245.         ||    (c == '#');
  246. }
  247.  
  248. /*
  249.  * Lookup a symbol in the symbol table
  250.  */
  251. lookup(symbol)
  252.     char *symbol;
  253. {
  254.     int i;
  255.     for(i=0; i < name_top; ++i)
  256.         if(!strcmp(symbol_names[i], symbol))
  257.             return i;
  258.     return -1;
  259. }
  260.  
  261. /*
  262.  * Log a symbol reference
  263.  */
  264. reference(symbol)
  265.     char *symbol;
  266. {
  267.     int s, i, j;
  268.  
  269. /* Check that symbol defined */
  270.     if((s = lookup(symbol)) == -1)
  271.         return;
  272.  
  273. /* Check that line not already reported */
  274.     j = ref_list[s+1];
  275.     for(i=ref_list[s]+1; i < j; ++i)
  276.         if(references[i] == line_number)
  277.             return;
  278.  
  279. /* Expand reference list to include new number */
  280.     if(ref_top >= REFERENCES)
  281.         error("Reference table full");
  282.     for(i = ref_top++; i > j; --i)
  283.         references[i] = references[i-1];
  284.  
  285. /* Adjust other symbols */
  286.     for(i=s+1; i <= name_top; ++i)
  287.         ++ref_list[i];
  288.  
  289.     references[j] = line_number;
  290. }
  291.  
  292. /*
  293.  * Define a new symbol
  294.  */
  295. define(symbol)
  296.     char *symbol;
  297. {
  298.     if(lookup(symbol) != -1) {
  299.         reference(symbol);
  300.         return; }
  301.  
  302.     if(name_top >= SYMBOLS)
  303.         error("Symbol table full");
  304.     symbol_names[name_top] = &symbol_pool[pool_top];
  305.     ref_list[name_top++] = ref_top;
  306.     do {
  307.         if(pool_top >= SYMBOL_POOL)
  308.             error("Symbol name space exausted");
  309.         symbol_pool[pool_top++] = *symbol; }
  310.     while(*symbol++);
  311.     references[ref_top++] = line_number;
  312. }
  313.  
  314. /*
  315.  * Write title for page
  316.  */
  317. title(string)
  318.     char *string;
  319. {
  320.     if(++pcount >= page_length) {
  321.         if(page_number)
  322.             putc('\f', stdout);
  323.         printf("%-30s %-30s Page: %u\n\n", filename, string, ++page_number);
  324.         pcount = 2; }
  325. }
  326.  
  327. /*
  328.  * Report an error in the file
  329.  */
  330. error(string)
  331.     char *string;
  332. {
  333.     fprintf(std